package com.pattern.beforeclass.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description
 * @Author Ping
 * @Date 2022/4/4 0:59
 **/
public class ProxyDemo {
    public static void main(String args[]) {
        TargetInterface targetObj = new TargetInterface() {
            @Override
            public int doSum(int a, int b) {
                return a + b;
            }
        } ;
        TargetInterface proxy1 = (TargetInterface) MyProxyFactory.getProxy(targetObj, MyProxyFactory.JDK_PROXY) ;
        System.out.println(proxy1.doSum(1,2) );
        TargetInterface proxy2 = (TargetInterface) MyProxyFactory.getProxy(targetObj, MyProxyFactory.CGLLIB_PROXY) ;
        System.out.println(proxy2.doSum(3,4) );


    }

}

interface TargetInterface {
    public int doSum(int a, int b) ;
}

class MyProxyFactory {
    public static final String JDK_PROXY = "jdkproxy" ;
    final static String CGLLIB_PROXY = "cglibproxy" ;
    public static Object getProxy(Object target, String type) {
        switch (type)
        {
            case JDK_PROXY:
                ClassLoader loader = MyProxyFactory.class.getClassLoader() ;
                Class [] its = target.getClass().getInterfaces() ;
                return Proxy.newProxyInstance(loader, its, new MyProxy(target)) ;
            case CGLLIB_PROXY:
                Enhancer enhancer = new Enhancer() ;
                enhancer.setSuperclass(target.getClass());
                enhancer.setCallback(new CGProxy());
                return enhancer.create() ;

        }
        return null ;
    }

}
class CGProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before invoked by CGLib.") ;
        Object ret = methodProxy.invokeSuper(o, objects) ;
        return ret;
    }
}
class MyProxy implements InvocationHandler {
    private Object targetObj ;

    public MyProxy(Object targetObj) {
        this.targetObj = targetObj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoked by JDK.") ;
        Object ret = method.invoke(targetObj, args) ;
        return ret;
    }
}
class User {
    int id ;
    String name ;

    public User() {
        this.id = new Random().nextInt(100) ;
        this.name = "user_" + this.id ;
    }
    public User(int id) {
        this.id = id ;
        this.name = "user_" + this.id ;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
interface UserService {
    public User getUserById(int id) ;
}
class UserServiceImpl implements  UserService{
    public User getUserById(int id) {
        System.out.println("Query from DB") ;
        User user = new User() ;
        user.setId(id) ;
        return user ;
    }
}

class UserServiceProxy implements UserService {
    UserService userService ;
    static Map<Integer, User> userCache = new ConcurrentHashMap<>( ) ;

    public UserServiceProxy(UserService userService) {
        this.userService = userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Override
    public User getUserById(int id) {
        if (userCache.containsKey(id)) {
            System.out.println("Get user from cache.") ;
            return userCache.get(id) ;
        }
        return this.userService.getUserById(id);
    }
}


